/* Copyright 2009 Sony Mathew, Minneapolis MN. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at  http://www.apache.org/licenses/LICENSE-2.0  Unless required by applicable law or agreed to in writing, software  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */
package com.xsm.gwt.widgets.client;

import java.util.Collection;

import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.user.client.ui.ListBox;
import com.xsm.gwt.widgets.client.LabelModel;
import com.xsm.gwt.widgets.client.LabelModel.LabelProvider;
import com.xsm.lite.util.EqualsBuilder;

/**
 * Manages a ListBox and provides utilities for it.
 * 
 * @author Sony Mathew
 */
public class ListBoxManager<T> {

    /**
     * A Simple interface that is equivalent to gwt's ChangeHandler but adds Type info.
     * 
     * @author Sony Mathew
     */
    public interface SelectionChangeHandler<T> {

        //Indicate when a change in value has occurred.
        public void onSelectionChange(T value);
    }
    
    private ListBox listBox = null;
    private LabelModel<T> labelModel = null;
    private SelectionChangeHandler<T> selChangeHandler = null;
    
    /**
     * author Sony Mathew
     */
    public ListBoxManager() {
        this(new ListBox());
    }
    
    /**
     * author Sony Mathew
     */
    public ListBoxManager(ListBox listBox) {
        this.listBox = listBox;
    }
    
    /**
     * Obtain the listbox being managed.
     * 
     * author Sony Mathew
     */
    public ListBox getListBox() {
        return listBox;
    }


    /**
     * Provide the objects to put into the listbox and provider of labels for each object.
     * 
     * author Sony Mathew
     */
    public void setList(Collection<T> objs, LabelProvider<T> labelProvider) {
        if (objs == null || objs.isEmpty()) {
            throw new IllegalArgumentException("Cannot provide empty list to ListBox");
        }
        listBox.clear();
        labelModel = new LabelModel<T>(objs, labelProvider);
        for(T o : objs) {
        	String label = labelProvider.getLabel(o);
            listBox.addItem(label);
        }
        listBox.setSelectedIndex(0);
    }
        
    /**
     * Select the specific object.
     * 
     * @param fire: Indicate whether a onSelectionChange should be fired.
     *       if true - will fire onSelectionChange(T) on the SelectionChangeHandler (if set).
     *       
     * author Sony Mathew
     */
    public void select(T o, boolean fire) {
        String selLabel = labelModel.getLabel(o);
        for(int i=0;i<listBox.getItemCount();i++) {
            String itemText = listBox.getItemText(i);
            if (EqualsBuilder.isEquals(selLabel, itemText)) {
                if (listBox.getSelectedIndex() != i) {
                    listBox.setSelectedIndex(i);
                    if (fire && selChangeHandler != null) {
                        selChangeHandler.onSelectionChange(o);
                    }                    
                }
                break;
            }
        }
    }
    
    /**
     * Select the specified object.
     * @see select(T, fire);
     * 
     * By default fires onSelectionChange.
     * 
     * author Sony Mathew
     */
    public void select(T o) {
        select(o, true);
    }
    
    public T getSelected() {
        int seli = listBox.getSelectedIndex();
        if (seli >= 0) {
            T o = labelModel.getObject(listBox.getValue(seli));
            return o;
        }
        
        throw new IllegalStateException("Unexpected, Nothing selected in ListBox");
    }
    
    /**
     * Provide a handler for selection changes.
     * 
     * author Sony Mathew
     */
    public void setSelectionChangeHandler(final SelectionChangeHandler<T> selChangeHandler) {
        this.selChangeHandler = selChangeHandler;
        listBox.addChangeHandler(new ChangeHandler() {
            public void onChange(ChangeEvent event) {
                selChangeHandler.onSelectionChange(getSelected());
            }
        });
        
    }
}
